package info.motteke.mybws.poi;

import info.motteke.mybws.AbstractNodeVisitor;
import info.motteke.mybws.node.CellNode;
import info.motteke.mybws.node.ExcelNode;
import info.motteke.mybws.node.IterationNode;
import info.motteke.mybws.node.SheetNode;
import info.motteke.mybws.node.TextNode;
import info.motteke.mybws.script.Scripter;
import info.motteke.mybws.script.ValueStack;

import java.util.Collection;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public class WriteVisitor extends AbstractNodeVisitor {

    private static final Logger logger = LogManager.getLogger(WriteVisitor.class);

    private final Workbook book;

    private final ValueStack stack;

    private Scripter scripter = new Scripter();

    private Sheet currentSheet;

    private Cell currentCell;

    private int iterationCount;

    public WriteVisitor(Workbook book, ValueStack stack) {
        this.book = book;
        this.stack = stack;
    }

    @Override
    public void visitExcel(ExcelNode excel) {
        logger.debug("visit : excel");
        visitChildren(excel);
    }

    @Override
    public void visitSheet(SheetNode sheet) {
        logger.debug("visit : sheet");
        currentSheet = book.createSheet(sheet.getName());
        iterationCount = 0;

        visitChildren(sheet);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void visitIteration(IterationNode iteration) {
        logger.debug("visit : iteration");
        Object obj = stack.get(iteration.getList());

        if (!(obj instanceof Collection)) {
            throw new IllegalArgumentException(iteration.getList() + " is not collection");
        }

        Collection<Object> collection = (Collection<Object>) obj;
        IterationStatus status = new IterationStatus(collection.size());

        iterationCount--;

        stack.push(status);

        for (Object var : collection) {
            iterationCount++;
            stack.push(var);
            visitChildren(iteration);
            stack.pop();

            status.next();
        }

        stack.pop();
    }

    @Override
    public void visitCell(CellNode cell) {
        logger.debug("visit : cell");
        currentCell = getCell(cell.getPosition());

        visitChildren(cell);
    }

    private Cell getCell(String position) {
        CellIndex index = CellIndex.toIndex(position);
        Row row = getRow(index.getRowIndex() + iterationCount);
        return getCell(row, index.getColumnIndex());
    }

    private Row getRow(int index) {
        Row row = currentSheet.getRow(index);

        if (row == null) {
            row = currentSheet.createRow(index);
        }

        return row;
    }

    private Cell getCell(Row row, int index) {
        Cell cell = row.getCell(index);

        if (cell == null) {
            cell = row.createCell(index);
        }

        return cell;
    }

    @Override
    public void visitText(TextNode text) {
        logger.debug("visit : text > " + text.getText());

        currentCell.setCellValue(scripter.parse(text.getText(), stack));
    }
}
